package nz.ac.massey.jbuif.view;

import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;
import java.util.regex.PatternSyntaxException;

import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import nz.ac.massey.jbuif.events.BeanActionEvent;
import nz.ac.massey.jbuif.events.BeanActionListener;
import nz.ac.massey.jbuif.events.BeanActionSupport;
import nz.ac.massey.jbuif.events.BeanActions;
import nz.ac.massey.jbuif.utils.Utils;

/**
 * list view class
 * @author ahkiouma
 *
 */
public class ListView extends JPanel implements IView, ListSelectionListener {

	private static final long serialVersionUID = 9170589139676257975L;

	private Object selectedObject;

	JList jl;
	private DefaultListModel model = new DefaultListModel();
	private DefaultListModel tempModel = new DefaultListModel();

	private BeanActionSupport bas;

	/**
	 * default constructore
	 */
	public ListView() {
		super();

		bas = new BeanActionSupport();

		jl = new JList(model) {
			
			private static final long serialVersionUID = 1L;

			public String getToolTipText(MouseEvent e) {
				
				if(tempModel.size() == 0)
				{
					return null;
				}
				
				int index = locationToIndex(e.getPoint());
				if (-1 < index) {
					String item = "<html><b>Class: </b><i>" +
									tempModel.getElementAt(index)
									.getClass()
									.getName()
									.toString()+"</i></html>";
					return item;
				} else {
					return "Unknown";
				}
			}
		};
		jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		jl.setCellRenderer(new CustomListRender());
		this.setLayout(new BorderLayout());
		this.add(new JScrollPane(jl), BorderLayout.CENTER);
		
		jl.addListSelectionListener(this);

		jl.addMouseListener(new MouseAdapter() {

			@Override
			public void mousePressed(MouseEvent e) {
				if (SwingUtilities.isRightMouseButton(e)) {
					jl.setSelectedIndex(getRow(e.getPoint()));

					JPopupMenu Pmenu = new JPopupMenu("Actions");
					
					// edit popup listener
					ActionListener edit = new ActionListener() {
						public void actionPerformed(ActionEvent e) {
//							System.out.println("[E]diting " + selectedObject +" of type "+selectedObject.getClass().getName());
							bas.fireBeanActionEvent(new BeanActionEvent(this,
									selectedObject, BeanActions.edit));
						}
					};
					JMenuItem editMenuItem = new JMenuItem("Edit Bean");
					Utils.setJMenuItemIcon(editMenuItem, "resources/edit.gif");

					Pmenu.add(editMenuItem);
					editMenuItem.addActionListener(edit);

					
					// clone object popup listener
					ActionListener clone = new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							
							// Implement clone
							bas.fireBeanActionEvent(new BeanActionEvent(this,
									selectedObject, BeanActions.clone));
						}
					};
					JMenuItem cloneMenuItem = new JMenuItem("Duplicate Bean");
					Utils.setJMenuItemIcon(cloneMenuItem, "resources/duplicate.gif");
					Pmenu.add(cloneMenuItem);
					cloneMenuItem.addActionListener(clone);
					

					// remove popup listener
					ActionListener deleteBean = new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							if (!model.isEmpty() && jl.getSelectedIndex() != -1) {
								if (JOptionPane
										.showConfirmDialog(
												null,
												("Are you sure you want to delete the bean: \n\n"
														+ "<html><b>" + model
														.get(jl
																.getSelectedIndex()))
														+ "</b></html>",
												"JBUIF",
												JOptionPane.YES_NO_OPTION) == 0) {
									
										// store the index of the selected item
										Object tempObj = jl.getSelectedValue();

										// remove the selected index from the
										// model
										model.removeElement(tempObj);
										bas.fireBeanActionEvent(new BeanActionEvent(
												this, tempObj,
												BeanActions.delete));
								}
							}
						}
					};
					JMenuItem delMenuItem = new JMenuItem("Delete Bean");
					Utils.setJMenuItemIcon(delMenuItem, "resources/delete.gif");
					Pmenu.add(delMenuItem);
					delMenuItem.addActionListener(deleteBean);

					Pmenu.addSeparator();

					// sort popup listener
					ActionListener sort = new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							if (!tempModel.isEmpty())
							{
								sort();
							}
						}
					};

					JMenuItem sortMenuItem = new JMenuItem("Sort beans");
					Utils.setJMenuItemIcon(sortMenuItem, "resources/sort.gif");
					Pmenu.add(sortMenuItem);
					sortMenuItem.addActionListener(sort);
					
					// disable menu items if nothing is selected
					if(jl.getSelectedIndex() == -1)
					{
						editMenuItem.setEnabled(false);
						cloneMenuItem.setEnabled(false);
						delMenuItem.setEnabled(false);
					}
					
					if(tempModel.size() == 0)
					{
						sortMenuItem.setEnabled(false);
					}

					Pmenu.show(e.getComponent(), e.getX(), e.getY());
				}
				
				// if double clicked on jlist
				if (e.getClickCount() == 2){
					bas.fireBeanActionEvent(new BeanActionEvent(this, selectedObject, BeanActions.edit));
				}
			}
	});
		setVisible(true);
	}

	
	/**
	 * clear the view
	 */
	@Override
	public void clearView() {
		model.removeAllElements();
		tempModel.removeAllElements();
	}

	
	/**
	 * get the selected object
	 * @return the selected object
	 */
	@Override
	public Object getSelectedObject() {
		return selectedObject;
	}

	
	/**
	 * set the selected object
	 * @param object an object
	 */
	@Override
	public void setSelectedObject(Object obj) {
		selectedObject = obj;
		jl.setSelectedValue(obj, true);
	}

	
	/**
	 * refresh the view
	 */
	@Override
	public void refreshView() {
		// TODO
		jl.validate();
		jl.repaint();
	}

	
	/**
	 * set the view
	 * @param objectCollection collection of objects
	 */
	@Override
	public void setView(Collection<Object> objCollection) {
		model.removeAllElements();
		tempModel.removeAllElements();

		// going through the objects and populate the model with them
		Iterator<Object> iter = objCollection.iterator();

		while (iter.hasNext()) {
			Object temp = iter.next();

			model.addElement(temp);
			tempModel.addElement(temp);
		}
	}

	
	/**
	 * sort the list
	 */
	@SuppressWarnings("unchecked")
	public void sort() {
		int size = model.getSize();
		Vector list = new Vector();
		for (int x = 0; x < size; ++x) {
			Object o = model.get(x);
			list.addElement(o);
		}

		// sort the List
		ObjectSorter<Object> objSorter = new ObjectSorter<Object>();
		objSorter.setSortByName(false);
		Collections.sort(list, objSorter);

		// update the model with a sorted List
		for (int x = 0; x < size; ++x) {
			if (model.getElementAt(x) != list.elementAt(x)) {
				model.set(x, list.elementAt(x));
			}
		}
	}

	
	/**
	 * getModel return the model
	 * @return instance of DefaultListModel
	 */
	public DefaultListModel getModel()
	{
		return model;
	}
	
	
	/**
	 * getRow return the row of selected item
	 * @param point refer to location of a item in the list
	 * @return index of the item
	 */
	private int getRow(Point point) {
		return jl.locationToIndex(point);
	}


	/**
	 * addObject add a component to the list
	 * @param obj
	 */
	public void addObject(String obj) {
		model.add(model.size(), obj);
		tempModel.add(model.size(), obj);
	}


	/**
	 * filter filter the components
	 * @param filter
	 */
	@Override
	public void filterList(String filter) {
		try{
			if (filter.length() > 0) {
				model.removeAllElements();
	
				for (int i = 0; i < tempModel.size(); i++) {
					if (tempModel.get(i).toString().matches(filter)) {
						model.addElement(tempModel.get(i));
					}
				}
			} else {
				model.clear();
				for (int i = 0; i < tempModel.size(); i++)
					model.addElement(tempModel.get(i));
			}
		}
		catch (PatternSyntaxException e){
//			System.out.println (e.toString());
		}
	}

	
	/**
	 * controlling the list value change
	 * @param e instance of ListSelectionEvent
	 */
	@Override
	public void valueChanged(ListSelectionEvent e) {
		if (e.getValueIsAdjusting() == false) {

			if (jl.getSelectedIndex() == -1) {
				setSelectedObject(null);
			} else {
				setSelectedObject(jl.getSelectedValue());
			}
		}
	}

	
	/**
	 * add a bean
	 * @param bal instance of BeanActionListener
	 */
	@Override
	public void addBeanActionListener(BeanActionListener bal) {
		bas.addBeanActionListener(bal);
	}

	
	/**
	 * remove a bean 
	 * @param bal instance of BeanActionListener
	 */
	@Override
	public void removeBeanActionListener(BeanActionListener bal) {
		bas.removeBeanActionListener(bal);
	}
}